package com.brave.mvvm.mvvmhelper.http

import com.orhanobut.logger.Logger
import okhttp3.*
import okio.Buffer
import java.io.IOException
import java.nio.charset.Charset
import kotlin.jvm.Throws

/**
 * ***author*** ：brave tou
 *
 * ***data***   : 2021/9/2 17:53
 *
 * ***desc***   : 网络请求拦截器
 * @param builder 构建者
 */
class LoggingInterceptor private constructor(private val builder: Builder) : Interceptor {
    private val charUtf8 = Charset.forName("UTF-8")

    @Throws(IOException::class)
    override fun intercept(chain: Interceptor.Chain): Response {
        // 获取原始的请求 originalRequest
        val originalRequest = chain.request()
        // 获取新的请求构建器 requestBuilder
        val requestBuilder = originalRequest.newBuilder()
        // 获取通用请求头
        val generalHeaders = builder.headers
        // 删除此构建器上的所有请求头并添加通用请求头
        requestBuilder.headers(generalHeaders)
        // 获取原始请求头 originalHeaders
        val originalHeaders = originalRequest.headers()
        // 获取原始请求头Key集合
        val names = originalHeaders.names()
        // 遍历原始请求头Key值
        for (name in names) {
            // 原始请求头Key是否为空
            if (!name.isNullOrEmpty()) {
                // 取出原始请求头Value
                val value = originalHeaders.get(name) ?: ""
                // 将原始请求头添加到新的请求构建器
                requestBuilder.addHeader(name, value)
            }
        }
        // 重定向请求路径
        val httpUrl = redirectHttpUrl(originalRequest, requestBuilder)
        // 获取处理后的新请求 request-header
        val request: Request = requestBuilder.url(
            httpUrl.newBuilder().build()
        ).build()
        // 获取请求参数
        if (this.builder.isDebug) {
            var paramsStr: String? = null
            var message: String? = null
            try {
                val requestBody = request.body()
                val buffer = Buffer()
                requestBody!!.writeTo(buffer)
                var charset = charUtf8
                val contentType = requestBody.contentType()
                if (contentType != null) {
                    charset = contentType.charset(charUtf8)
                }
                paramsStr = buffer.readString(charset!!)
            } catch (e: Exception) {
                message = e.message
            }
            Logger.e(
                "TAG -> ${this.builder.getTag(true)}\n" +
                        "请求参数<头部> -> %s\n" +
                        "请求参数<参数> -> %s\n" +
                        "请求参数<异常> -> %s\n" +
                        "请求参数<网址> -> %s ",
                request.headers(),
                paramsStr,
                message,
                httpUrl
            )
        }
        // 记录开始请求数据的时间
        val startTime = System.currentTimeMillis()
        val response = chain.proceed(request)
        // 计算请求数据到响应数据所用时间
        val intervalTime = System.currentTimeMillis() - startTime
        if (this.builder.isDebug) {
            val responseBody = response.body()
            val source = responseBody!!.source()
            source.request(Long.MAX_VALUE)
            val buffer = source.buffer
            var charset = charUtf8
            val contentType = responseBody.contentType()
            if (contentType != null) {
                charset = contentType.charset(charUtf8)
            }
            val json = buffer.clone().readString(charset!!)
            Logger.e(
                "TAG -> ${this.builder.getTag(false)}\n" +
                        "响应参数<时间> -> %sms\n" +
                        "响应参数<网址> -> %s\n" +
                        "响应参数<头部> -> %s\n" +
                        "响应参数<数据> -> %s ",
                intervalTime,
                response.request().url(),
                response.headers(),
                json
            )
        }
        return response
    }

    /**
     * 重定向请求路径
     *
     * @param request 请求
     * @param builder 请求构建器
     */
    private fun redirectHttpUrl(request: Request, builder: Request.Builder): HttpUrl {
        // 获取原始的请求路径 httpUrl
        val httpUrl = request.url()
        // 获取原始请求头
        val headers = request.headers()
        // 获取原始请求头的Key集合
        val headerNames = headers.names()
        // 取出重定向Map
        this.builder.redirects.forEach { (key, value) ->
            // 重定向Key值不为空
            if (key.isNotEmpty()) {
                // 遍历原始请求Key值
                for (name in headerNames) {
                    // 原始请求头Key是否为空
                    if (!name.isNullOrEmpty()) {
                        // 重定向Key值 等于 原始请求头的Name
                        if (key == name) {
                            // 获取需要替换的路径
                            val needReplacedUrl = if (this.builder.baseUrl.isEmpty()) {
                                headers.get(name) ?: ""
                            } else {
                                this.builder.baseUrl
                            }
                            // 把需要替换的路径 替换为重定向指定路径
                            val url = httpUrl.toString()
                                .replace(needReplacedUrl, value)
                            // 删除重定向请求头
                            builder.removeHeader(name)
                            // 返回HttpUrl
                            return HttpUrl.parse(url) ?: httpUrl
                        }
                    }
                }
            }
        }
        // 返回默认HttpUrl
        return httpUrl
    }

    class Builder {
        // 是否开启Debug日志
        internal var isDebug = false

        // 主Api
        internal var baseUrl = ""

        // 通用TAG
        private var tag = "MvvmHelper"

        // 请求TAG
        private var requestTag: String = "MvvmHelperRequest"

        // 响应TAG
        private var responseTag: String = "MvvmHelperResponse"

        // 通用请求头
        private val builder: Headers.Builder = Headers.Builder()
        val headers: Headers
            get() = builder.build()

        // 重定向替换Map
        internal val redirects: MutableMap<String, String> = mutableMapOf()

        /**
         * 获取拦截器专用TAG
         * @param isRequest 是否为请求TAG
         */
        fun getTag(isRequest: Boolean): String {
            return if (isRequest) {
                if (requestTag.isEmpty()) tag else requestTag!!
            } else {
                if (responseTag.isEmpty()) tag else responseTag!!
            }
        }

        /**
         * 设置是否打印日志
         */
        fun loggable(isDebug: Boolean): Builder {
            this.isDebug = isDebug
            return this
        }

        /**
         * 设置主Api
         */
        fun baseUrl(baseUrl: String): Builder {
            this.baseUrl = baseUrl
            return this
        }

        /**
         * 设置拦截器通用TAG
         */
        fun tag(tag: String): Builder {
            if (tag.isNotEmpty()) {
                this.tag = tag
            }
            return this
        }

        /**
         * 设置请求专用TAG
         */
        fun request(tag: String): Builder {
            this.requestTag = tag
            return this
        }

        /**
         * 设置响应专用TAG
         */
        fun response(tag: String): Builder {
            this.responseTag = tag
            return this
        }

        /**
         * 添加通用请求头
         */
        fun addHeader(name: String, value: String): Builder {
            if (name.isNotEmpty()) {
                builder[name] = value
            }
            return this
        }

        /**
         * 添加重定向指向
         * @param key 对应请求头的name
         * @param value 需要替换的请求网址
         */
        fun addRedirect(key: String, value: String): Builder {
            if (key.isNotEmpty()) {
                redirects[key] = value
            }
            return this
        }

        fun build(): LoggingInterceptor {
            addHeader("mvvm", "helper")
            return LoggingInterceptor(this)
        }
    }
}